package cn.quevo.spring.util;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import cn.quevo.core.lang.NumberUtils;
import org.apache.tools.ant.taskdefs.condition.Http;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.MediaType;
import org.springframework.ui.Model;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import cn.quevo.core.enums.EnumsInterface;
import cn.quevo.core.lang.JSONUtils;
import cn.quevo.core.lang.StringUtils;

/**
 * 获取request上下文工具类
 *
 * @author July july_sky@foxmail.com
 * @date 2017年6月30日 下午6:15:22
 * @Copyright ©2015-2035 湘豫(北京)科技有限公司. All Rights Reserved.
 */
public class WebUtils extends org.springframework.web.util.WebUtils {
    private static Logger log = LoggerFactory.getLogger(WebUtils.class);

    /**
     * 获取HttpServletRequest<br/>
     * 需要在web.xml配置org.springframework.web.context.request.RequestContextListener<br/>
     *
     * @return
     * @author July july_sky@foxmail.com
     * @date 2016年10月12日上午11:13:11
     */
    public static HttpServletRequest getHttpServletRequest() {
        return getHttpServletRequest(false);
    }

    /**
     * 获取HttpServletRequest<br/>
     * 需要在web.xml配置org.springframework.web.context.request.RequestContextListener<br/>
     *
     * @param requestLog
     * @return
     * @author July july_sky@foxmail.com
     * @date 2016年10月12日上午11:13:11
     */
    public static HttpServletRequest getHttpServletRequest(Boolean... requestLog) {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes())
          .getRequest();
        if (requestLog == null || (requestLog.length > 0 && requestLog[0])) {
            parseHttpRequest(request);
        }
        return request;
    }

    /**
     * 获取HttpServletResponse
     *
     * @return
     */
    public static HttpServletResponse getHttpServletResponse() {
        return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
    }

    /**
     * 获得项目跟路径
     *
     * @return
     * @author July july_sky@foxmail.com
     * @date 2016年10月17日下午6:59:36
     */
    public static String getURI() {
        HttpServletRequest request = getHttpServletRequest();
        String path = request.getContextPath();
        path = path.endsWith("/") ? path.substring(0, path.length() - 1) : path;
        String port = request.getServerPort() == 80 ? "" : (":" + request.getServerPort());
        return request.getScheme() + "://" + request.getServerName() + port + path;
    }

    /**
     * 此方法期望异步执行
     *
     * @param request
     * @author July july_sky@foxmail.com
     * @date 2016年10月17日下午6:59:43
     */
    public static void parseHttpRequest(HttpServletRequest request) {
        Map<String, Object> logMap = new HashMap<>();
        logMap.put("cookies", request.getCookies());

        Map<String, String[]> params = request.getParameterMap();
        logMap.put("params", params);

        Enumeration<String> enumeration = request.getHeaderNames();
        Map<String, Object> _map = new HashMap<>();
        String name = "";
        if (enumeration != null) {
            while (enumeration.hasMoreElements()) {
                name = enumeration.nextElement();
                _map.put(name, request.getHeader(name));
            }
        }
        logMap.put("headers", _map);

        _map = new HashMap<>();
        HttpSession session = request.getSession();
        enumeration = session.getAttributeNames();
        if (enumeration != null) {
            while (enumeration.hasMoreElements()) {
                name = enumeration.nextElement();
                _map.put(name, session.getAttribute(name));
            }
        }
        logMap.put("sessionAttrs", _map);

        _map = new HashMap<>();
        enumeration = request.getAttributeNames();
        if (enumeration != null) {
            while (enumeration.hasMoreElements()) {
                name = enumeration.nextElement();
                _map.put(name, request.getAttribute(name));
            }
        }
        logMap.put("requestAttrs", _map);
        try {
            log.debug(JSONUtils.format(logMap));
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
    }

    /**
     * 获得Session
     *
     * @return
     * @author July july_sky@foxmail.com
     * @date 2016年10月17日下午7:00:10
     */
    public static HttpSession getHttpSession() {
        return getHttpSession(false);
    }

    /**
     * 获得Session值
     *
     * @param name
     * @return
     * @author July july_sky@foxmail.com
     * @date 2016年10月17日下午7:00:19
     */
    public static Object getHttpSession(String name) {
        return getHttpSession().getAttribute(name);
    }

    /**
     * 获得Session
     *
     * @param requestLog
     * @return
     * @author July july_sky@foxmail.com
     * @date 2016年10月17日下午7:00:30
     */
    public static HttpSession getHttpSession(Boolean... requestLog) {
        return getHttpServletRequest(requestLog).getSession();
    }

    /**
     * 设置Session
     *
     * @param key
     * @param value
     * @author July july_sky@foxmail.com
     * @date 2016年10月17日下午7:00:36
     */
    public static void setHttpSession(String key, Object value) {
        setHttpSession(key, value, false);
    }

    /**
     * 设置Session
     *
     * @param key
     * @param value
     * @param requestLog
     * @author July july_sky@foxmail.com
     * @date 2016年10月17日下午7:00:46
     */
    public static void setHttpSession(String key, Object value, Boolean... requestLog) {
        getHttpSession(requestLog).setAttribute(key, value);
    }

    /**
     * 获得上级页面
     *
     * @return
     * @author July july_sky@foxmail.com
     * @date 2016年10月17日下午7:00:50
     */
    public static String getReferer() {
        return getHttpServletRequest(false).getHeader("Referer");
    }

    /**
     * 页面跳转(重定向)
     *
     * @param view
     * @return
     * @author July july_sky@foxmail.com
     * @date 2016年10月17日下午7:01:03
     */
    public static String toRedirect(String view) {
        return "redirect:" + view;
    }

    /**
     * 页面跳转(转发)
     *
     * @param view
     * @return
     * @author July july_sky@foxmail.com
     * @date 2016年10月17日下午7:01:03
     */
    public static String forward(String view) {
        return "forward:" + view;
    }

    /**
     * 跳转到错误页面
     *
     * @param model
     * @param errorPage
     * @param enums
     * @return
     * @author July july_sky@foxmail.com
     * @date 2016年10月17日下午7:01:09
     */
    public static String toError(Model model, String errorPage, EnumsInterface enums) {
        model.addAttribute("error", "[" + enums.getCode() + "]" + enums.getValue());
        return errorPage;
    }

    /**
     * 跳转到错误页面
     *
     * @param model
     * @param errorPage
     * @param msgInfo
     * @return
     * @author July july_sky@foxmail.com
     * @date 2016年10月17日下午7:01:16
     */
    public static String toError(Model model, String errorPage, String msgInfo) {
        model.addAttribute("error", msgInfo);
        return errorPage;
    }

    /**
     * 跳转到错误页面
     *
     * @param model
     * @param msgInfo
     * @return
     * @author July july_sky@foxmail.com
     * @date 2016年10月17日下午7:01:22
     */
    public static String toError(Model model, String msgInfo) {
        model.addAttribute("error", msgInfo);
        return "/error";
    }

    /**
     * 跳转到错误页面
     *
     * @author July july_sky@foxmail.com
     * @date 2017-11-26 14:34:57
     * @Copyright ©2015-2035 湘豫(北京)科技有限公司. All Rights Reserved.
     * @version 1.0  * @param model 模型数据  * @param errorPage 错误页面  * @param code
     * 错误编码  * @param msg 错误信息  * @return
     */
    public static String toError(Model model, String errorPage, String code, String msg) {
        model.addAttribute("error", "[" + code + "]" + msg);
        return errorPage;
    }

    /**
     * 获取URL所有参数
     *
     * @param url
     * @return
     * @author July july_sky@foxmail.com
     * @date 2016年12月8日下午10:28:29
     */
    public static Map<String, String> analysisUrlParams(String url) {
        Map<String, String> params = new HashMap<>();
        if (StringUtils.isBlank(url) || url.indexOf("?") == -1) {
            return params;
        }
        url = url.substring(url.indexOf("?") + 1);
        String[] args = url.split("\\&");
        if (args != null) {
            String[] tmp = null;
            String key = "";
            String val = "";
            for (String arg : args) {
                tmp = arg.split("=");
                if (!StringUtils.isBlank(tmp[0])) {
                    key = tmp[0].trim();
                    val = tmp.length == 2 && !StringUtils.isBlank(tmp[1]) ? tmp[1].trim() : "";
                    if (StringUtils.isBlank(params.get(key))) {
                        params.put(key, val);
                    } else {
                        params.put(key, params.get(key) + "##" + val);
                    }
                }
            }
        }
        return params;
    }

    /**
     * 获取URL中指定参数
     *
     * @param url
     * @return
     * @author July july_sky@foxmail.com
     * @date 2016年12月8日下午10:28:29
     */
    public static String getUrlFirstParams(String url, String name) {
        if (StringUtils.isBlank(url) || url.indexOf("?") == -1) {
            return "";
        }
        url = url.substring(url.indexOf("?") + 1);
        String[] args = url.split("\\&");
        if (args != null) {
            String[] tmp = null;
            for (String arg : args) {
                tmp = arg.split("=");
                if (!StringUtils.isBlank(tmp[0]) && tmp[0].trim().equals(name)) {
                    return tmp.length == 2 && !StringUtils.isBlank(tmp[1]) ? tmp[1].trim() : "";
                }
            }
        }
        return "";
    }

    /**
     * 从Session或者Cookie获取值
     *
     * @param name
     */
    public static String getSessionOrCookie(String name) {
        Object obj = getHttpSession(name);
        if (obj == null) {
            obj = getCookie(name);
        }
        return obj == null ? null : StringUtils.valueOf(obj);
    }

    /**
     * 从Session或者Cookie获取值
     *
     * @param name
     */
    public static <T> T getSessionOrCookie(String name, Class<T> cls) {
        Object obj = getHttpSession(name);
        if (!StringUtils.isBlank(obj)) {
            return (T) obj;
        }
        String val = getCookie(name);
        if (StringUtils.isBlank(val) || !val.startsWith("{")) {
            return null;
        }
        return JSONUtils.parse(val, cls);
    }

    /**
     * 设置Session并且新增到Cookie
     *
     * @param name
     * @param value
     * @param response
     */
    public static void setSessionAndCookie(String name, String value, HttpServletResponse response) {
        setHttpSession(name, value);
        addCookie(name, value, response);
    }

    /**
     * 设置Session并且新增到Cookie
     *
     * @param name
     * @param value
     * @param response
     */
    public static void setSessionAndCookie(String name, Long value, HttpServletResponse response) {
        setHttpSession(name, value);
        addCookie(name, StringUtils.valueOf(value), response);
    }

    /**
     * 设置Session并且新增到Cookie
     *
     * @param name
     * @param value
     * @param response
     */
    public static void setSessionAndCookie(String name, Object value, HttpServletResponse response) {
        setHttpSession(name, value);
        addCookie(name, JSONUtils.format(value), response);
    }

    /**
     * 新增Cookie
     *
     * @param name
     * @param value
     * @param response
     */
    public static void addCookie(String name, String value, HttpServletResponse response) {
        Cookie cookie = new Cookie(name, value);
        response.addCookie(cookie);
    }

    /**
     * 获取cookie内容
     *
     * @param name
     * @return
     * @author July july_sky@foxmail.com
     * @date 2016年12月8日下午10:42:04
     */
    public static String getCookie(String name) {
        Cookie[] cookies = WebUtils.getHttpServletRequest().getCookies();
        if (cookies == null || cookies.length <= 0) {
            return "";
        }
        for (Cookie cookie : cookies) {
            if (cookie.getName().equals(name)) {
                return cookie.getValue();
            }
        }
        return "";
    }

    public static Map<String, String> getParameterMap(HttpServletRequest request, String perx) {
        Map<String, String> _result = new HashMap<>();
        Map<String, String[]> params = request.getParameterMap();
        String key = "";
        String value[] = null;
        int length = perx.length();
        for (Map.Entry<String, String[]> entry : params.entrySet()) {
            key = entry.getKey();
            value = entry.getValue();
            if (!StringUtils.isBlank(key) && value != null && value.length > 0 && key.startsWith(perx)) {
                _result.put(key.substring(length), StringUtils.join(value, ","));
            }
        }
        return _result;
    }

    public static String getIpAddr() {
        HttpServletRequest request = WebUtils.getHttpServletRequest();
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }

    public static String getShortURI() {
        HttpServletRequest request = WebUtils.getHttpServletRequest();
        String path = request.getContextPath();
        if (path.endsWith("/")) {
            path = path.substring(0, path.length() - 1);
        }
        String port = ":" + request.getServerPort();
        return request.getScheme() + "://" + request.getServerName() + port + path;
    }

    /**
     * 判断是否Ajax请求
     *
     * @param request
     * @return
     * @author July july_sky@foxmail.com
     * @date 2017年12月4日 下午6:24:04
     */
    public static boolean isAjax(HttpServletRequest request) {
        if (!StringUtils.isBlank(request.getHeader("x-requested-with")) || StringUtils.isBlank(request.getHeader("x-ajax"))) {
            return true;
        }

        if (StringUtils.isBlank(request.getParameter("formater"))) {
            return false;
        }
        String formatter = request.getParameter("formater").trim();
        return formatter.equalsIgnoreCase("json") || formatter.equalsIgnoreCase("xml");
    }

    /**
     * 直接写入内容
     *
     * @param response
     * @param msg
     * @author July july_sky@foxmail.com
     * @date 2017年12月8日 上午11:02:31
     */
    public static void response(HttpServletResponse response, String msg) {
        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setContentType(MediaType.APPLICATION_PROBLEM_JSON_UTF8_VALUE);
        response.setCharacterEncoding("UTF-8");
        try (PrintWriter writer = response.getWriter();) {
            writer.write(StringUtils.isBlank(msg) ? "error" : msg);
            writer.flush();
        } catch (IOException e) {
            log.error(e.getMessage(), e);
        }
    }

    /**
     * 直接写入内容
     *
     * @param response
     * @param msg
     * @author July july_sky@foxmail.com
     * @date 2017年12月8日 上午11:02:31
     */
    public static void response(HttpServletResponse response, Object msg) {
        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setContentType(MediaType.APPLICATION_PROBLEM_JSON_UTF8_VALUE);
        response.setCharacterEncoding("UTF-8");
        try (PrintWriter writer = response.getWriter();) {
            writer.write(StringUtils.isBlank(msg) ? "error"
              : ((msg instanceof String) ? msg.toString() : JSONUtils.format(msg)));
            writer.flush();
        } catch (IOException e) {
            log.error(e.getMessage(), e);
        }
    }
}
